﻿using System;
using System.Diagnostics;
using Smarly.Idml.RelaxNg.Generator.Model;
using Tenuto.Grammar;

namespace Smarly.Idml.RelaxNg.Generator.Proxy
{
	public abstract class BuilderBase
	{
		protected BuilderBase(Action<IObjectName> updateName)
		{
			UpdateName = updateName ?? (obj => { });
		}

		[DebuggerStepThrough]
		public virtual IStruct Fill(IStruct getStruct = null)
		{
			return getStruct ?? CreateIStruct();
		}

		public abstract IStruct CreateIStruct();

		protected readonly Action<IObjectName> UpdateName;

		[DebuggerStepThrough]
		public static BuilderBase Factory(Expression exp, Action<IObjectName> updateName)
		{
			if (exp is GroupExp)
				return new GroupExpBuilder((GroupExp)exp, updateName);

			if (exp is AttributeExp)
				return new AttributeExpBuilderBase((AttributeExp)exp, updateName);

			if (exp is DataExp)
				return new DataExpBuilder((DataExp)exp, updateName);

			if (exp is ReferenceExp)
				return new ReferenceExpBuilder((ReferenceExp)exp, updateName);

			if (exp is ValueExp)
				return new ValueExpBuilder((ValueExp)exp, updateName);

			if (exp is ListExp)
				return new ListExpBuilder((ListExp)exp, updateName);

			if (exp is ChoiceExp)
				return new ChoiceExpBuilder((ChoiceExp)exp, updateName);

			if (exp is Expression.TextExp)
				return new ExpressionTextExpBuilder((Expression.TextExp)exp, updateName);

			if (exp is InterleaveExp)
				return new InterleaveExpBuilder((InterleaveExp)exp, updateName);

			if (exp is OneOrMoreExp)
				return new OneOrMoreExpBuilder((OneOrMoreExp)exp, updateName);

			if (exp is ElementExp)
				return new ElementExpBuilder((ElementExp)exp, updateName);

			throw new NotImplementedException();
		}
	}

	public abstract class Builder<T> : BuilderBase where T : Expression
	{
		[DebuggerStepThrough]
		protected Builder(T exp, Action<IObjectName> updateName) : base(updateName)
		{
			Exp = exp;
		}

		protected T Exp { get; private set; }

		protected bool IsNull { get { return Exp.IsNullable; } }

		public override IStruct CreateIStruct()
		{
			throw new NotImplementedException("For " + Exp.GetType().FullName + " called Builder<T>::CreateIStruct");
		}
	}
}